<?php

/**
 * 数据库驱动核心类
 *
 * @author jonwang(jonwang@myqee.com)
 * @category   MyQEE
 * @package    System
 * @subpackage Core
 * @copyright  Copyright (c) 2008-2011 myqee.com
 * @license    http://www.myqee.com/license.html
 */
abstract class MyQEE_Database_Driver
{

    /**
     * 当前使用的链接，会在master和slaver之前自动切换
     * @return resource a MySQL link identifier on success&return.falseforfailure;.
     * @var mysqli
     */
    protected $_connection;

    // Identifier for this connection within the PHP driver
    protected $_connection_id;

    protected $_connection_master_id;

    protected $_connection_slaver_id;

    /**
     * 主连接
     */
    protected $_connection_master;

    /**
     * 从连接
     */
    protected $_connection_slaver;

    /**
     * 最后查询SQL语句
     *
     * @var string
     */
    protected $last_query = '';

    /**
     * 当前配置
     * @var array
     */
    protected $config;

    // Character that is used to quote identifiers
    protected $_identifier = '"';

    protected $_as_table = array();

    /**
     * 记录事务
     * array(
     * '连接ID'=>'父事务ID',
     * '连接ID'=>'父事务ID',
     * ...
     * )
     * @var array
     */
    protected static $transactions = array();

    /**
     * 记录hash对应的host数据
     * @var array
     */
    protected static $_hash_to_hostname = array();

    public function __construct($config)
    {
        $this->config = $config;
        if ( ! is_array($this->config['connection']['hostname']) )
        {
            # 主从链接采用同一个内存地址
            $this->_connection_slaver = & $this->_connection_master;
            $this->_connection_slaver_id = & $this->_connection_master_id;
        }
    }

    public function __destruct()
    {
        $this->close_connect();
    }

    /**
     * 构建SQL语句
     */
    abstract public function compile($builder, $type = 'selete');

    /**
     * 查询
     * @param string $sql 查询语句
     * @param string $as_object 是否返回对象
     * @param boolean $use_master 是否使用主数据库，不设置则自动判断
     * @return Database_Driver_MySQLI_Result
     */
    abstract public function query($sql, $as_object = null, $use_master = null);

    /**
     * 连接数据库
     * @param boolean $use_master 是否使用主数据库
     */
    abstract public function connect($use_master = true);

    /**
     * 关闭链接
     */
    abstract public function close_connect();

    /**
     * Sanitize a string by escaping characters that could cause an SQL
     * injection attack.
     *
     * $value = $db->escape('any string');
     *
     * @param   string   value to quote
     * @return  string
     */
    abstract public function escape($value);

    abstract public function quote_table($value);

    /**
     * Quote a value for an SQL query.
     *
     * $db->quote(NULL);   // 'NULL'
     * $db->quote(10);     // 10
     * $db->quote('fred'); // 'fred'
     *
     * Objects passed to this function will be converted to strings.
     * [QueryBuilder_Expression] objects will use the value of the expression.
     * [Database_Query] objects will be compiled and converted to a sub-query.
     * All other objects will be converted using the `__toString` method.
     *
     * @param   mixed   any value to quote
     * @return  string
     * @uses    Database::escape
     */
    abstract public function quote($value);

    /**
     * 获取事务对象
     *
     * @return Database_Transaction
     */
    public function transaction()
    {
        $tr_name = 'Database_Driver_'.$this->config['type'].'_Transaction';
        if ( !class_exists($tr_name,true) )
        {
            throw new Exception(__('the transaction of :driver not exist.',array(':driver'=>$this->config['type'])));
        }
        return new $tr_name($this);
    }

    /**
     * 获取连接唯一ID
     *
     * @return string
     */
    public function connection_id()
    {
        return $this->_connection_id;
    }

    /**
     * 获取一个随机HOST
     *
     * @param boolean $use_master
     */
    protected function _get_rand_host($use_master)
    {
        $hostname = $this->config['connection']['hostname'];
        if ( ! is_array($hostname) ) return $hostname;
        if ( $use_master )
        {
            $hostconfig = $hostname['master'];
        }
        else
        {
            $hostconfig = $hostname['slaver'];
        }
        if ( is_array($hostconfig) )
        {
            $count = count($hostconfig);
            # 获取一个随机链接
            $rand_id = mt_rand(0, $count - 1);
            return $hostconfig[$rand_id];
        }
        else
        {
            return $hostconfig;
        }
    }

    /**
     * 获取链接唯一hash
     * @param string $hostname
     * @param int $port
     * @param string $username
     * @return string
     */
    protected function _get_connection_hash($hostname, $port, $username)
    {
        $hash = sha1(get_class($this) . '_' . $hostname . '_' . $port . '_' . $username);
        Database_Driver::$_hash_to_hostname[$hash] = array('hostname' => $hostname, 'port' => $port, 'username' => $username);
        return $hash;
    }

    /**
     * 根据数据库连接唯一hash获取数据信息
     * @param string $has
     * @return array array('hostname'=>'','port'=>'','username'=>'')
     */
    protected static function _get_hostname_by_connection_hash($hash)
    {
        return Database_Driver::$_hash_to_hostname[$hash];
    }
}